#include <iostream>
#include <fstream>

#include "Ship.h"
#include "BattleShip.h"
#include "PartOfBattle.h"
#include "Utils.h"

#define ENABLE_SCAN 1

using namespace std;
int total = 0;

#if ENABLE_SCAN
SetOfEncode setOfBattle;

int Scan(BattleShipPtr _battle, int _type)
{
	int count = 0;

	//exit condition
	if (_type < Ship::DESTROYER) 
	{
		int encode = _battle->EncodeInt32();
		setOfBattle.insert(encode);
		total ++;
		return 1;
	}
	//don't put
	count += Scan(_battle->Clone(),_type-1);

	//try to putship
	for (int i=0;i<MAX_H/2;i++)
	for (int j=0;j<MAX_V/2;j++)
	{
		BattleShipPtr newBattle = _battle->Clone();
		ShipPtr newShip(new Ship((Ship::TypeOfShip)_type,i,j,Ship::HORIZONTAL));
		if (newBattle->PutShip(newShip))
		{
			count += Scan(newBattle,_type-1);
		}
		/*
		unsigned int encode = _battle->EncodeInt32() ;
		if (i==0 && j==0 && _type == Ship::DESTROYER)
		{
			std::cout << _battle->EncodeInt32() << endl;
		}
		*/
		ShipPtr newShip2(new Ship((Ship::TypeOfShip)_type,i,j,Ship::VERTICAL));
		BattleShipPtr newBattle2 = _battle->Clone();
		if (newBattle2->PutShip(newShip2))
		{
			count += Scan(newBattle2,_type-1);
			//encode = newBattle2->EncodeInt32();
			//cout << encode << endl;
		}

	}
	if (Ship::SUBMARINE == _type)
		cout << "SUBMARINE: total = " <<total << ". Size = " << setOfBattle.size() << endl;
	else if (Ship::BATTLE == _type)
		cout << "BATTLE: total = " << total << ". Size = " << setOfBattle.size() << endl;
	/*
	else if (Ship::PATROL == _type)
		cout << "PATROL: total = "<<total << endl;*/
	//cout << "Current: total = "<< total << endl;
	return count;
}

int Scan1(BattleShipPtr _battle)
{
	int count = 0;
	for (int i=0; i<MAX_H/2;i++)
		for (int j=0;j<MAX_V/2;j++)
		{
			for (int k = Ship::DESTROYER; k<=Ship::AIRCRAFT;k++)
			{
				{
					ShipPtr newShip(new Ship((Ship::TypeOfShip)k,i,j,Ship::HORIZONTAL));
					BattleShipPtr newBattle = _battle->Clone();
					if (newBattle->PutShip(newShip))
					{
						count ++;
						int encode = newBattle->EncodeInt32();
						std::cout << count << ":" << encode << endl;
						setOfBattle.insert(encode);
					}
				}
				{
					ShipPtr newShip(new Ship((Ship::TypeOfShip)k,i,j,Ship::VERTICAL));
					BattleShipPtr newBattle = _battle->Clone();
					if (newBattle->PutShip(newShip))
					{
						count ++;
						int encode = newBattle->EncodeInt32();
						std::cout << count << ":" << encode << endl;
						setOfBattle.insert(encode);
					}
				}
			}
		}
	return count;
}

void TestScan1()
{
	BattleShipPtr battle(new BattleShip());
	cout << "total: "<< Scan1(battle) << endl;
	cout << "Size: " << setOfBattle.size() << endl;
}

void TestFullScan()
{
	BattleShipPtr battle(new BattleShip());
	//unsigned int encode = battle->EncodeInt32();
	cout << "total: "<< Scan(battle,Ship::AIRCRAFT) << endl;
	cout << "Size: " << setOfBattle.size() << endl;
}
void ExportToFile()
{
	TestFullScan();
	ofstream myfile;
	myfile.open("data.txt");
	SetOfEncode::iterator ii;
	myfile << setOfBattle.size() << endl;
	for (ii = setOfBattle.begin(); ii != setOfBattle.end(); ii++)
	{
		myfile << (*ii) << endl;
	}
	myfile.close();
}

void ExportToFile2()
{
	Utils::GetInstance()->LoadFromFile();
	ListOfEncode encodeSet = Utils::GetInstance()->GetSetOfBattle();
	PartOfBattlePtr part (new PartOfBattle(false,false));
	part->InsertPosibility(encodeSet);

	ofstream myfile;
	myfile.open("data2.txt");
	SetOfEncode::iterator ii;
	for (int i=0;i<MAX_H/2;i++)
		for (int j=0;j<MAX_V/2;j++)
		{
			int count = part->GetCount(Point(i,j));
			myfile << count << endl;			
		}

	myfile.close();
}
#endif

void TestPartOfBattle()
{
	//generate
	BattleShipPtr battle(new BattleShip);
	ShipPtr ship(new Ship(Ship::DESTROYER,0,0,Ship::VERTICAL));
	battle->PutShip(ship);
	unsigned int encode = battle->EncodeInt32();
	PartOfBattlePtr part (new PartOfBattle(false,false));
	ListOfEncode encodeSet = Utils::GetInstance()->GetSetOfBattle();
	//SetOfEncode encodeSet;
	//encodeSet.insert(encode);
	part->InsertPosibility(encodeSet);
	std::cout << "Encode: " << encode << endl;
	cout << "Contain: " << part->GetCount(Point(1,0)) << endl;
	part->SetValue(Point(0,0),true);
	cout << "Contain: " << part->GetCount(Point(1,0)) << endl;
}

void TestEncode()
{
	ShipPtr ship(new Ship(Ship::SUBMARINE,0,0,Ship::HORIZONTAL));
	BattleShipPtr battle(new BattleShip());
	if (battle->PutShip(ship))
	{
		unsigned int encode = battle->EncodeInt32();
		cout << "encode: " << encode << endl;
		cout << "Contain: " << PartOfBattle::GetValue(encode,4,3) << endl;
	}
}

void TestLoadFile()
{
	ListOfEncode encodeSet = Utils::GetInstance()->GetSetOfBattle();
	cout << "Size: " << encodeSet.size() << endl;
}

void TestGuessPos()
{
	Utils::GetInstance()->Initialize();
	Point p = Utils::GetInstance()->GuessPos();
	cout << "1:" << p.first << ":" << p.second << endl;
	Utils::GetInstance()->ProcessPos(Point(0,4),true);
	p = Utils::GetInstance()->GuessPos();
	cout << "2:"<<p.first << ":" << p.second << endl;
	Utils::GetInstance()->ProcessPos(Point(0,3),false);
	p = Utils::GetInstance()->GuessPos();
	cout << "3:"<<p.first << ":" << p.second << endl;
	Utils::GetInstance()->ProcessPos(Point(0,5),true);
	Utils::GetInstance()->FoundShip(Point(0,5),Ship::DESTROYER);
	p = Utils::GetInstance()->GuessPos();
	cout << "4:"<<p.first << ":" << p.second << endl;
}

void TestFindShip()
{
	ShipPtr ship(new Ship(Ship::AIRCRAFT,3,3,Ship::HORIZONTAL));
	BattleShipPtr battle(new BattleShip());
	if (battle->PutShip(ship))
	{
		ShipPtr ship2 = battle->FindShip(Point(3,8),Ship::AIRCRAFT);
		if (ship2)
		{
			PointSet posSet = ship2->GetPos();
			Point p = *posSet.begin();
			cout << p.first << ":" << p.second << endl;
		}
	}
}

void TestRemoveShipType()
{
	Utils::GetInstance()->Initialize();
	Utils::GetInstance()->ProcessPos(Point(3,4),true);
	Utils::GetInstance()->ProcessPos(Point(4,4),true);
	Utils::GetInstance()->FoundShip(Point(4,4),Ship::DESTROYER);
	//Utils::GetInstance()->Join();
	Point p = Utils::GetInstance()->GuessPos();
	cout << p.first << ":" << p.second << endl;
	Utils::GetInstance()->ProcessPos(Point(7,5),false);
	p = Utils::GetInstance()->GuessPos();
	cout << p.first << ":" << p.second << endl;
	Utils::GetInstance()->ProcessPos(Point(8,5),true);
	p = Utils::GetInstance()->GuessPos();
	cout << p.first << ":" << p.second << endl;
}

int main()
{
	TestGuessPos();
	//ExportToFile2();
	//TestFullScan();
	//ExportToFile();
	//TestFindShip();
	//TestRemoveShipType();
	//ExportToFile2();
	system("pause");
	return 0;
}